"""
构建数据依赖图
基于已知的 Operation 数据依赖关系（比如 LLM 分析的结果），构建有向图。

计划支持两种输入：
1.LLM 输出作为输入，类似 load_checkout_dependencies。
2.analyze_protobuf_dependency 脚本输出作为输入，将两个脚本连起来。
"""

import json
from pathlib import Path
from typing import Dict, List, Set


class DependencyGraph:
    """数据依赖图"""
    
    def __init__(self):
        """初始化依赖图"""
        self.operations = set()  # 所有的 Operation 端点
        self.fields = set()  # 所有的字段
        self.dependencies = []  # 依赖关系列表
        self.adjacency_matrix = None  # 邻接矩阵（Operation 级别）
        self.field_correlation_matrix = None  # 字段关联矩阵
        
    def add_dependency(self, source_op: str, target_op: str, 
                      source_field: str, target_field: str,
                      dep_type: str, description: str = ""):
        """
        添加一个依赖关系
        
        Args:
            source_op: 源 Operation
            target_op: 目标 Operation
            source_field: 源字段
            target_field: 目标字段
            dep_type: 依赖类型（强依赖/弱依赖）
            description: 说明
        """
        self.operations.add(source_op)
        self.operations.add(target_op)
        self.fields.add(source_field)
        self.fields.add(target_field)
        
        self.dependencies.append({
            'source_op': source_op,
            'target_op': target_op,
            'source_field': source_field,
            'target_field': target_field,
            'dep_type': dep_type,
            'description': description
        })
    
    def build_adjacency_matrix(self) -> Dict:
        """
        构建 Operation 级别的邻接矩阵
        
        Returns:
            Dict: 邻接矩阵（字典格式）
        """
        ops_list = sorted(self.operations)
        matrix = {}
        
        # 填充邻接矩阵（只记录非零值）
        for src_op in ops_list:
            matrix[src_op] = {}
            for tgt_op in ops_list:
                count = sum(1 for dep in self.dependencies 
                           if dep['source_op'] == src_op and dep['target_op'] == tgt_op)
                if count > 0:
                    matrix[src_op][tgt_op] = count
        
        self.adjacency_matrix = matrix
        return self.adjacency_matrix
    
    def build_field_correlation_matrix(self) -> Dict:
        """
        构建字段关联矩阵（对称矩阵）
        显示哪些字段在依赖关系中共现
        
        Returns:
            Dict: 字段关联矩阵（字典格式）
        """
        fields_list = sorted(self.fields)
        matrix = {}
        
        # 填充关联矩阵（对称，只记录非零值）
        for src_field in fields_list:
            matrix[src_field] = {}
            for tgt_field in fields_list:
                # 统计这两个字段一起出现的次数（对称）
                count = 0
                for dep in self.dependencies:
                    if (dep['source_field'] == src_field and dep['target_field'] == tgt_field) or \
                       (dep['source_field'] == tgt_field and dep['target_field'] == src_field):
                        count += 1
                if count > 0:
                    matrix[src_field][tgt_field] = count
        
        self.field_correlation_matrix = matrix
        return self.field_correlation_matrix
    
    def get_operation_stats(self) -> List[Dict]:
        """
        获取每个 Operation 的统计信息
        
        Returns:
            List[Dict]: 包含入度和出度的统计
        """
        ops_list = sorted(self.operations)
        stats = []
        
        for op in ops_list:
            # 计算出度（作为源的次数）
            out_degree = sum(1 for dep in self.dependencies if dep['source_op'] == op)
            
            # 计算入度（作为目标的次数）
            in_degree = sum(1 for dep in self.dependencies if dep['target_op'] == op)
            
            stats.append({
                'operation': op,
                'in_degree': in_degree,
                'out_degree': out_degree,
                'total_degree': in_degree + out_degree
            })
        
        return stats
    
    def get_field_stats(self) -> List[Dict]:
        """
        获取每个字段的统计信息
        
        Returns:
            List[Dict]: 字段出现次数统计
        """
        fields_list = sorted(self.fields)
        stats = []
        
        for field in fields_list:
            # 作为源字段的次数
            as_source = sum(1 for dep in self.dependencies if dep['source_field'] == field)
            
            # 作为目标字段的次数
            as_target = sum(1 for dep in self.dependencies if dep['target_field'] == field)
            
            stats.append({
                'field': field,
                'as_source_count': as_source,
                'as_target_count': as_target,
                'total_count': as_source + as_target
            })
        
        return stats
    

    
    def export_to_json(self, output_file: str):
        """
        导出为 JSON 格式
        
        Args:
            output_file: 输出文件路径
        """
        data = {
            'summary': {
                'total_operations': len(self.operations),
                'total_fields': len(self.fields),
                'total_dependencies': len(self.dependencies),
                'strong_dependencies': sum(1 for dep in self.dependencies if dep['dep_type'] == '强依赖'),
                'weak_dependencies': sum(1 for dep in self.dependencies if dep['dep_type'] == '弱依赖')
            },
            'operations': sorted(self.operations),
            'fields': sorted(self.fields),
            'dependencies': self.dependencies,
            'operation_stats': self.get_operation_stats(),
            'field_stats': self.get_field_stats(),
            'adjacency_matrix': self.adjacency_matrix if self.adjacency_matrix is not None else {},
            'field_correlation_matrix': self.field_correlation_matrix if self.field_correlation_matrix is not None else {}
        }
        
        with open(output_file, 'w', encoding='utf-8') as f:
            json.dump(data, f, ensure_ascii=False, indent=2)
        
        print(f"数据依赖图已导出到: {output_file}")
    
    def print_summary(self):
        """打印图的摘要信息"""
        print("\n" + "="*80)
        print("数据依赖图摘要")
        print("="*80)
        print(f"Operation 节点数: {len(self.operations)}")
        print(f"字段数: {len(self.fields)}")
        print(f"依赖关系数: {len(self.dependencies)}")
        print(f"强依赖数: {sum(1 for dep in self.dependencies if dep['dep_type'] == '强依赖')}")
        print(f"弱依赖数: {sum(1 for dep in self.dependencies if dep['dep_type'] == '弱依赖')}")
        print("="*80)


def load_checkout_dependencies() -> DependencyGraph:
    """
    加载 Checkout 服务的依赖关系数据
    
    Returns:
        DependencyGraph: 构建好的依赖图
    """
    graph = DependencyGraph()
    
    # 根据提供的依赖表添加数据
    dependencies_data = [
        (1, "PlaceOrderRequest", "CartService.GetCart", "user_id", "user_id", "强依赖", "根据用户ID获取购物车"),
        (3, "ProductCatalogService.GetProduct", "CurrencyService.Convert", "price_usd", "from", "强依赖", "转换商品价格货币"),
        (4, "PlaceOrderRequest", "CurrencyService.Convert", "user_currency", "to_code", "强依赖", "目标货币代码"),
        (6, "PlaceOrderRequest", "ShippingService.GetQuote", "address", "address", "强依赖", "收货地址用于运费计算"),
        (7, "ShippingService.GetQuote", "CurrencyService.Convert", "cost_usd", "from", "强依赖", "转换运费货币"),
        (8, "PlaceOrderRequest", "CurrencyService.Convert", "user_currency", "to_code", "强依赖", "目标货币代码"),
        (10, "PlaceOrderRequest", "PaymentService.Charge", "credit_card", "credit_card", "强依赖", "信用卡信息用于支付"),
        (11, "PlaceOrderRequest", "ShippingService.ShipOrder", "address", "address", "强依赖", "收货地址用于创建物流订单"),
        (13, "PlaceOrderRequest", "CartService.EmptyCart", "user_id", "user_id", "强依赖", "清空用户购物车"),
        (14, "PlaceOrderRequest", "EmailService.SendOrderConfirmation", "email", "email", "弱依赖", "发送确认邮件"),
    ]
    
    for item in dependencies_data:
        seq, src_op, tgt_op, src_field, tgt_field, dep_type, desc = item
        graph.add_dependency(src_op, tgt_op, src_field, tgt_field, dep_type, desc)
    
    return graph


def main():
    """主函数"""
    import argparse
    
    parser = argparse.ArgumentParser(description='构建数据依赖图')
    parser.add_argument('--output_file', type=str, default='./data/mock/dependency_graph.json',
                        help='输出JSON文件路径')
    
    args = parser.parse_args()
    
    # 创建输出目录
    output_path = Path(args.output_file)
    output_path.parent.mkdir(parents=True, exist_ok=True)
    
    # 加载依赖数据
    print("正在构建依赖图...")
    graph = load_checkout_dependencies()
    
    # 打印摘要
    graph.print_summary()
    
    # 构建矩阵
    print("\n正在构建邻接矩阵...")
    graph.build_adjacency_matrix()
    
    print("正在构建字段关联矩阵...")
    graph.build_field_correlation_matrix()
    
    # 打印 Operation 统计
    print("\n" + "="*80)
    print("Operation 统计信息")
    print("="*80)
    op_stats = graph.get_operation_stats()
    for stat in op_stats:
        print(f"{stat['operation']:<50} 入度:{stat['in_degree']:>3} 出度:{stat['out_degree']:>3} 总计:{stat['total_degree']:>3}")
    
    # 打印字段统计
    print("\n" + "="*80)
    print("字段统计信息")
    print("="*80)
    field_stats = graph.get_field_stats()
    for stat in field_stats:
        print(f"{stat['field']:<30} 作为源:{stat['as_source_count']:>3} 作为目标:{stat['as_target_count']:>3} 总计:{stat['total_count']:>3}")
    
    # 导出 JSON
    print("\n正在导出JSON文件...")
    graph.export_to_json(args.output_file)
    
    print("\n完成！")


if __name__ == '__main__':
    main()
